#include <vector>
#include <cstdint>

#include "QueueManager.hpp"
#include "PointCloudFrame.hpp"
#include "DiagnosticAPI.hpp"
#include "HawkeyeFrame.hpp"

namespace aeye {

namespace detail {

template<typename T>
T QueueManagerInternal<T>::pop() {
  std::unique_lock<decltype(m_)> lk{m_};
  while (queue_.empty()) {
    cv_.wait_for(lk, std::chrono::milliseconds(100));
    if (!is_running_) {
      lk.unlock();
      cv_.notify_all();
      return {};
    }
  }
  T data = std::move(queue_.front());
  queue_.pop();
  lk.unlock();
  cv_.notify_all();
  return data;
}

template<typename T>
bool QueueManagerInternal<T>::empty() const {
  std::lock_guard<decltype(m_)> lk{m_};
  return queue_.empty();
}

template<typename T>
size_t QueueManagerInternal<T>::size() const {
  std::lock_guard<decltype(m_)> lk{m_};
  return queue_.size();
}

template<typename T>
const T &QueueManagerInternal<T>::front() const {
  std::lock_guard<decltype(m_)> lk{m_};
  return queue_.front();
}

template<typename T>
const T &QueueManagerInternal<T>::back() const {
  std::lock_guard<decltype(m_)> lk{m_};
  return queue_.back();
}

template<typename T>
void QueueManagerInternal<T>::clean() noexcept {
  std::lock_guard<decltype(m_)> lk{m_};
  while (!queue_.empty()) {
    queue_.pop();
  }
}

template<typename T>
QueueManagerInternal<T>::QueueManagerInternal(const std::atomic<bool> &is_running, size_t max)
    : is_running_(is_running), max_queue_size_(max) {}

template class QueueManagerInternal<std::vector<uint8_t>>;
template class QueueManagerInternal<PointCloudFrame>;
template class QueueManagerInternal<HawkeyeFrame>;
template class QueueManagerInternal<DiagnosticData>;

}

}
